#include "planetcache.h"

#include "planet.h"
#include "planetcell.h"

namespace infinity {

Planet::Cache::Cache(const Vector3i& capacity)
:	m_capacity(capacity)
,	m_origin(Vector3i::zero)
,	m_dimensions(Vector3i::zero)
,	m_isValid(false)
,	m_cells(NULL)
{
	resize(capacity);
}

Planet::Cache::~Cache()
{
	delete [] m_cells;
}

void Planet::Cache::resize(const Vector3i& capacity)
{
	m_capacity = capacity;

	delete [] m_cells;

	dw::uint32 totalSize = m_capacity.x * m_capacity.y * m_capacity.z;

	m_cells = new Cell [totalSize];

	m_isValid = false;
}

void Planet::Cache::invalidate()
{
	m_isValid = false;
}

void Planet::Cache::prefetch(const Planet* planet, const Vector3i& origin, const Vector3i& dimensions)
{
	dwAssert(m_cells != NULL, "Invalid internal state");
	dwAssert(dimensions.x >= 0 && dimensions.x <= m_capacity.x, "Invalid parameter : dimensions are invalid");
	dwAssert(dimensions.y >= 0 && dimensions.y <= m_capacity.y, "Invalid parameter : dimensions are invalid");
	dwAssert(dimensions.z >= 0 && dimensions.z <= m_capacity.z, "Invalid parameter : dimensions are invalid");

	dw::uint32 requestSize = dimensions.x * dimensions.y * dimensions.z;

	m_origin = origin;
	m_dimensions = dimensions;

	Vector3i pos;
	dw::uint32 cellIndex;

	for (dw::int32 k = 0; k < dimensions.z; ++k)
	{
		pos.z = origin.z + k;
		for (dw::int32 j = 0; j < dimensions.y; ++j)
		{
			pos.y = origin.y + j;
			for (dw::int32 i = 0; i < dimensions.x; ++i)
			{
				pos.x = origin.x + i;

				cellIndex = k * m_dimensions.y * m_dimensions.x + j * m_dimensions.x + i;

				planet->getCell(pos, m_cells[cellIndex]);
			}
		}
	}

	m_isValid = true;
}

bool Planet::Cache::isValid() const
{
	return m_isValid;
}

void Planet::Cache::getCell(const Vector3i& position, Planet::Cell& cell) const
{
	Vector3i internalPos = position - m_origin;

	dwAssert(internalPos.x >= 0 && internalPos.x < m_dimensions.x, "Invalid parameter : position is not in cache");
	dwAssert(internalPos.y >= 0 && internalPos.y < m_dimensions.y, "Invalid parameter : position is not in cache");
	dwAssert(internalPos.z >= 0 && internalPos.z < m_dimensions.z, "Invalid parameter : position is not in cache");

	cell = m_cells[internalPos.z * m_dimensions.y * m_dimensions.x + internalPos.y * m_dimensions.x + internalPos.x];
}

} // namespace infinity
